#pragma once
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>
#include <strings.h>
#include <sys/select.h>
#include "Log.hpp"

const int num = sizeof(fd_set) * 8;
class SelectServer
{

public:
    SelectServer(uint16_t port) : _port(port), _isrunning(false), _listensock(-1)
    {
    }

    void Init(int backlog)
    {
        // 创建监听sock
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            LOG(Abnormal, "create listen sock error\n");
            exit(1);
        }
        int opt = 1;
        setsockopt(_listensock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
        struct sockaddr_in addr;
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(_port);
        addr.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_listensock, (struct sockaddr *)(&addr), sizeof(addr));
        if (n < 0)
        {
            LOG(Abnormal, "bind listen sock error\n");
            exit(1);
        }

        n = listen(_listensock, backlog);
        if (n < 0)
        {
            LOG(Abnormal, "listen listen sock error\n");
            exit(1);
        }

        // 初始化rfds
        for (int i = 0; i < num; i++)
        {
            rfds[i] = -1;
        }
        rfds[0] = _listensock;
    }

    void ReadHandler(fd_set *fds)
    {
        // LOG(Debug, "读条件就绪\n");
        for (int i = 0; i < num; i++)
        {
            if (rfds[i] != -1 && FD_ISSET(rfds[i], fds)) // 读条件就绪
            {
                if (_listensock == rfds[i])
                {
                    // 有新的文件描述符到来
                    struct sockaddr_in addr;
                    socklen_t len = sizeof(addr);
                    int newsock = accept(_listensock, (struct sockaddr *)(&addr), &len);
                    if (newsock < 0)
                    {
                        // 获取连接失败，继续循环检测其他文件描述符
                        LOG(Abnormal, "connection establishment failed\n");
                        continue;
                    }

                    int pos = 0;
                    for (; pos < num; pos++)
                    {
                        if (rfds[pos] == -1)
                        {
                            rfds[pos] = newsock;
                            break;
                        }
                    }
                    if (pos == num)
                    {
                        // select承受的文件描述符已满，对于新到来的连接及逆行关闭处理
                        close(newsock);
                        LOG(Abnormal, "the number of connection carriers is full\n");
                    }
                }
                else
                {
                    char buffer[1024];
                    int n = read(rfds[i], buffer, sizeof(buffer) - 1);
                    if(n > 0)
                    {
                        buffer[n] = 0;
                        std::cout << "client say# " << buffer << endl;
                    }
                    else
                    {
                        close(rfds[i]);
                        rfds[i] = -1;
                    }
                }
            }
        }
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            fd_set fds;
            FD_ZERO(&fds);
            int max_fd = -1;
            for(int i = 0; i < num; i++)
            {
                if(rfds[i] != -1)
                {
                    FD_SET(rfds[i], &fds);
                    max_fd = max(max_fd, rfds[i]);
                }
            }

            struct timeval tm;
            memset(&tm, 0, sizeof(tm));
            tm.tv_sec = 1;

            int n = select(max_fd + 1, &fds, nullptr, nullptr, &tm);
            switch (n)
            {
            case 0:
                LOG(Info, "read condition not ready\n");
                break;
            case -1:
                break;
            default:
                ReadHandler(&fds);
                break;
            }
            PrintBug();
        }
        _isrunning = false;
    }

    void PrintBug()
    {
        std::cout << "conn list: ";
        for (int i = 0; i < num; i++)
        {
            if (rfds[i] != -1)
            {
                std::cout << rfds[i] << " ";
            }
        }
        std::cout << std::endl;
    }

    ~SelectServer() {}

private:
    uint16_t _port;
    int _listensock;
    bool _isrunning;

    int rfds[num];
};
